package com.itdianzi.controller.shiro;

import com.itdianzi.domain.system.Module;
import com.itdianzi.domain.system.User;
import com.itdianzi.service.system.ModuleService;
import com.itdianzi.service.system.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class AuthRealm extends AuthorizingRealm {
    @Autowired
    private ModuleService moduleService;
    /**
     * 授权方法的执行时机 取决于xml的配置
     * 如果配置了需要某些权限才可以访问 才执行授权   /system/module/list.do = perms["模块管理"]
     * 当执行的地址栏有访问这样的路径时候才执行匹配
     *
     * 方法名称:获得授权信息 , 用于判断是否具备某些权限
     * 参数
     * @param// principals 安全 数据
     * @return AuthorizationInfo 权限的信息
     * 根据登录的信息查询权限的信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获得用户，获得主要的安全数据（用户数据）
        User user =(User) principalCollection.getPrimaryPrincipal();
        //2.根据RBAC获得权限数据
        List<Module> moduleList = moduleService.findByUser(user);

        //3.构造shiro需要的权限信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //构造权限列表数据
        Set<String> stringPermissions = new HashSet<>();

        //将moduleList转换成set集合
        for (Module module : moduleList) {
            stringPermissions.add(module.getName());//将权限信息放入
        }

        info.setStringPermissions(stringPermissions);

        return info;

    }




@Autowired
private UserService userService;
    /**
     * 认证
     * 看方法名称 : 获得认证(登录)的信息
     * 看参数   : AuthenticationToken 其实就是 UsernamePasswordToken , 封装了用户在页面输入的数据
     * 看返回值 : AuthenticationInfo 认证数据(查询到数据库后返回的数据,必须是安全数据)
     *
     * @param //token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1.获取用户在页面输入的用户名和密码
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;

        String email = upToken.getUsername();//用户输入的用户名

        String password = new String(upToken.getPassword());//用户的密码
        //2.查询数据库得到User对象,  只是查是否有这个用户
        User user = userService.findByEmail(email);

        //3.最后需要认证信息
        //SimpleAuthenticationInfo info = new SimpleAuthenticationInfo();
        /**
         *  public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)
         *  参数1: 安全数据 用户对象 user(必须查询数据库得到)
         *  参数2: 密码( 数据库中用户的密码 )
         *  参数3: realmName 域的名称 随意 只要唯一即可  this.getName() 当前类名
         */
        //参数2:其实可以不传 但是 传入的原因是以后方便获得密码数据
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
        //当info对象已经构建完成之后，自动执行密码比较器的方法 如果没有构建完成，直接抛出异常
        //构造数据
        return info;//如果没有查询到User对象，直接抛出异常

    }
}
